<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>基本用法</title>
</head>
<body>

<div id="app">
    <input type="text" v-focus>
</div>

<div id="app1">
    <div v-test:msg.a.b="message"></div>
</div>

<div id="app2">
    <div v-test="{msg:'hello',name:'Envy'}"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
    /**
     * 自定义指令的注册方法和组件很像，也分全局注册和局部注册，比如注册一个v-focus的指令，用于在<input>、<textarea>元素初始化时自动获得焦点。
     * 写法和组件基本类似，只是方法名称由component修改为directive。
     * **/

    // //全局注册
    // Vue.directive('focus',{
    //     //指令选项
    // });
    //
    // //局部注册
    // new Vue({
    //     el:"#app",
    //     directives:{
    //         focus:{
    //             //指令选项
    //         }
    //     }
    // });
    //上面的两种方式都只是注册了自定义指令v-focus，还没有实现具体的功能，下面介绍自定义指令的各个选项。
    //自定义指令的选项是由几个钩子函数组成的，每个都是可选的。

    /**
     *
     * bind：只调用一次，指令第一次绑定到元素时调用，用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
     *
     * inserted：被绑定元素插入父节点时调用（父节点存在即可调用，不必存在于document中）。
     *
     * update：被绑定元素所在的模板更新时调用，而不论绑定值是否变化。通过比较更新前后的绑定值，可以忽略不必要的模板更新。
     *
     * componentUpdated：被绑定元素所在模板完成一次更新周期时调用。
     *
     * unbind：只调用一次，指令与元素解绑时调用。
     * **/

    //可以根据需求在不同的钩子函数内完成逻辑代码。如在上面的v-focus中，我们希望在元素插入父节点时就调用，那最好就使用inserted。
    Vue.directive("focus", {
        inserted: function (el) {
            //聚焦元素
            el.focus();
        }
    });

    var app = new Vue({
        el: "#app"
    });

    /**
     *
     * 每个钩子函数都有几个参数可用，如前面使用到的el，它们的含义如下：
     * el：指令所绑定的元素，可以直接操作DOM；
     * -------------------------------
     * binding：一个对象，包含以下属性：
     * name：指令名，不包含v-前缀；
     * value：指令的绑定值，如v-my-directive="1+1",则value的值是2。
     * oldValue：指令绑定的前一个值，仅在update和componentUpdated钩子中使用。无论值是否改变都可用。
     * expression：绑定值的字符串形式。如v-my-directive="1+1",则expression的值是"1+1"。
     * arg：传给指令的参数。如v-my-directive:foo，arg的值是foo。
     * modifiers：一个包含修饰符的对象。如v-my-directive.foo.bar，修饰符对象modifiers的值是{foo:true,bar:true}。
     *---------------------
     * vnode：Vue编译生成的虚拟节点。
     * oldVnode：上一个虚拟节点仅在update和componentUpdated钩子中可用。
     * **/

    Vue.directive("test", {
        bind: function (el, binding, vnode) {
            var keys = [];
            for (var i in vnode) {
                keys.push(i);
            }
            el.innerHTML =
                'name：' + binding.name + "<br>" +
                'value：' + binding.value + "<br>" +
                'expression：' + binding.expression + "<br>" +
                'argument：' + binding.arg + "<br>" +
                'modifiers：' + JSON.stringify(binding.modifiers) + "<br>" +
                'vnode keys：' + keys.join(",")
        }
    });

    var app1 = new Vue({
        el:"#app1",
        data:{
            message:"some text"
        }
    });

    /**
     *
     * 在大多数使用场景下，我们会在bind钩子里绑定一些事件，比如在document上用addEventListener绑定，在unbind里使用removeEventListener解绑，
     * 比较典型的实例就是让这个元素随着鼠标拖拽。
     *
     * **/

    /**
     *
     * 如果需要使用多个值，自定义指令也可以传入一个JavaScript对象字面量，只要是合法类型的JavaScript表达式都是可以的。
     *
     * **/

    Vue.directive("test",{
        bind:function (el,binding,vnode) {
            console.log(binding.value.msg);
            console.log(binding.value.name);
        }
    });

    var app2 = new Vue({
        el:"#app2",
    })
</script>
</body>
</html>
